package com.tbit.uqbike.push.util;


import com.tbit.uqbike.push.pojo.Point;

import java.util.ArrayList;
import java.util.List;

/**
 * 电子围栏工具类
 *
 * @author Leon
 * 2017年12月13日 下午7:57:27
 */
public class GeoUtil {
    private static final double EARTH_RADIUS = 6371.137;

    /**
     * 经纬度字符串转points
     *
     * @param pointString
     * @return
     */
    public static List<Point> getPoints(String pointString) {
        List<Point> points = new ArrayList<>();

        String[] pointArray = pointString.split(";");
        for (int i = 0; i < pointArray.length; i++) {
            String[] lonlat = pointArray[i].split(",");
            if (lonlat.length == 2) {
                points.add(new Point(Double.parseDouble(lonlat[0]), Double.parseDouble(lonlat[1])));
            }
        }

        return points;
    }

    /**
     * Points转字符串
     *
     * @param points
     * @return
     */
    public static String getPointToString(List<Point> points) {
        StringBuilder result = new StringBuilder();
        int size = points.size();
        for (int i = 0; i < size; i++) {
            Point point = points.get(i);
            result.append(point.getX()).append(",").append(point.getY());

            if (i != (size - 1)) {
                result.append(";");
            }
        }

        return result.toString();
    }

    /**
     * 获取电子围栏的中心
     *
     * @param points
     * @return
     */
    public static Point GetCenterPoint(List<Point> points) {
        // 以下为简化方法（400km以内）
        int total = points.size();
        double lat = 0, lon = 0;
        for (Point p : points) {
            lat += p.getX() * Math.PI / 180;
            lon += p.getY() * Math.PI / 180;
        }
        lat /= total;
        lon /= total;
        return new Point(lat * 180 / Math.PI, lon * 180 / Math.PI);
    }

    /***
     * 获取点到多边形的距离
     * @param point
     * @param points
     * @return
     */
    public static Double getDistance(Point point, List<Point> points) {
        /** 最近的边 */
        Double distanceShort = Double.MAX_VALUE;
        Integer len = points.size();
        Integer maxIndex = len - 1;
        for (int i = 0; i < len; i++) {
            double temp;
            //多边形中当前点
            Point currentPoint = points.get(i);
            Point nearPoint = maxIndex == i ? points.get(0) : points.get(i + 1);
            double a, b, c;
            a = getDistance(point, currentPoint);//点与多边形一点的距离
            b = getDistance(point, nearPoint);//点与多边形一点的距离
            c = getDistance(currentPoint, nearPoint);//多边形邻边距离
            if (a * a >= b * b + c * c) {
                temp = b;
            } else if (b * b >= c * c + a * a) {
                temp = a;
            } else {
                double l = (a + b + c) / 2;     //周长的一半
                double s = Math.sqrt(l * (l - a) * (l - b) * (l - c));  //海伦公式求面积
                Double ss = 2 * s / c;
                /** c为斜边，最近距离*/
                temp = ss;
            }
            /** b为斜边 */
            if (distanceShort > temp) {
                distanceShort = temp;
            }
        }
        return distanceShort;
    }

    /**
     * 检测点是否在多边形内
     *
     * @param point
     * @param points
     * @return
     */
    public static boolean IsPtInPoly(Point point, List<Point> points) {
        boolean flag = false;
        int n = points.size();
        Point dp = point;
        Point[] dps = new Point[n];
        points.toArray(dps);
        for (int i = 0; i < n; i++) {
            if (dp.getY() < dps[i].getY() && dp.getY() < dps[(i + 1) % n].getY()) {
                continue;
            }
            if (dps[i].getX() <= dp.getX() && dps[(i + 1) % n].getX() <= dp.getX()) {
                continue;
            }
            double dx = dps[(i + 1) % n].getX() - dps[i].getX();
            double dy = dps[(i + 1) % n].getY() - dps[i].getY();
            double t = (dp.getX() - dps[i].getX()) / dx;
            double y = t * dy + dps[i].getY();
            if (y <= dp.getY() && t >= 0 && t <= 1) {
                flag = !flag;
            }
        }
        return flag;
    }

    /**
     * 获取两点之间的距离返回米
     */
    public static double getDistance(Point p1, Point p2) {
        double lon1 = (Math.PI / 180) * p1.getX();
        double lon2 = (Math.PI / 180) * p2.getX();
        double lat1 = (Math.PI / 180) * p1.getY();
        double lat2 = (Math.PI / 180) * p2.getY();

        // 地球半径
        double R = 6371;
        double d = Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1)) * R;
        // 转换成千米（根据自己需求）

        return d * 1000;
    }

    /**
     * 获取两点之间的距离返回米
     */
    public static double getDistanceNew(Point p1, Point p2) {
        // 纬度
        double lat1 = Math.toRadians(p1.getY());
        double lat2 = Math.toRadians(p2.getY());
        // 经度
        double lng1 = Math.toRadians(p1.getX());
        double lng2 = Math.toRadians(p2.getX());
        // 纬度之差
        double a = lat1 - lat2;
        // 经度之差
        double b = lng1 - lng2;
        // 计算两点距离的公式
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
                Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(b / 2), 2)));
        // 弧长乘地球半径, 返回单位: 千米
        s = s * EARTH_RADIUS;
        return s * 1000;
    }

    /***
     * 获取点到多边形的距离
     * @param point
     * @param points
     * @return
     */
    public static Double getDistanceNew(Point point, List<Point> points) {
        /** 最近的边 */
        Double distanceShort = null;
        Integer len = points.size();
        Integer maxIndex = len - 1;
        for (int i = 0; i < len; i++) {
            // 多边形中当前点
            Point currentPoint = points.get(i);
            Point nearPoint = maxIndex == i ? points.get(0) : points.get(i + 1);
            double a, b, c;
            a = getDistanceNew(point, currentPoint);// 点与多边形一点的距离
            b = getDistanceNew(point, nearPoint);// 点与多边形一点的距离
            c = getDistanceNew(currentPoint, nearPoint);// 多边形邻边距离
            if (a * a >= b * b + c * c) {
                /** a为斜边 */
                if (distanceShort == null || distanceShort > b) {
                    distanceShort = b;
                }

                continue;
            }
            if (b * b >= c * c + a * a) {
                /** b为斜边 */
                if (distanceShort == null || distanceShort > a) {
                    distanceShort = a;
                }

                continue;
            }

            double l = (a + b + c) / 2; // 周长的一半
            double s = Math.sqrt(l * (l - a) * (l - b) * (l - c)); // 海伦公式求面积
            Double ss = 2 * s / c;
            if (distanceShort == null) {
                /** c为斜边，最近距离 */
                distanceShort = ss;
            }
        }
        return distanceShort;
    }

}
